package com.example.JavaWebApi.core.neo4j;

import com.example.JavaWebApi.core.mybatisplusextention.wrapperCreator.ConnectorType;
import com.example.JavaWebApi.core.mybatisplusextention.wrapperCreator.OperatorType;
import com.example.JavaWebApi.core.mybatisplusextention.wrapperCreator.model.QueryConditionModel;
import lombok.Data;

import java.util.*;
import java.util.function.Consumer;

/**
 * @program: lvzhengcao_api
 * @description:
 * @author: 杨泽
 * @create: 2023-11-15 14:53
 */
public abstract class Neo4jAbstractQueryWrapper {
    protected List<QueryConditionModel> conditionModelList=new ArrayList<>();
    protected List<String> appendSqls=new ArrayList<>();
    protected HashMap<String,Object> parameters=new HashMap<>();
    protected HashMap<String, Map<String,Object>> objectMap=new HashMap<>();
    protected String finalConditionCql="";
    protected String finalOrderCql="";
    protected HashMap<String,String> objectCql=new HashMap<>();
    protected List<String> orderByAsc=new ArrayList<>();
    protected List<String> orderByDesc=new ArrayList<>();
    protected Boolean hasBuild=false;
    protected Integer itemIndex=0;
    public String getFinalConditionCql(){
        return finalConditionCql;
    }
    public HashMap<String,Object> getParameters(){
        return parameters;
    }
    public String getFinalOrderCql(){
        return finalOrderCql;
    }
    public HashMap<String,String> getObjectCql(){
        return objectCql;
    }
    /**
     * Description: 等于
     * @param condition 为true拼接条件 false不拼接
     * @param column 查询字段
     * @param value 值
     * @return com.example.JavaWebApi.core.neo4j.Neo4jQueryWrapper
     * @author 杨泽
     * @date 2023/11/2 11:25
     */
    protected void baseEq(boolean condition,String column,Object value){
        if(condition){
            QueryConditionModel queryConditionModel=createCondition(column,value, ConnectorType.And, OperatorType.Equal);
            conditionModelList.add(queryConditionModel);
        }
    }
    protected void baseNe(boolean condition,String column,Object value){
        if(condition){
            QueryConditionModel queryConditionModel=createCondition(column,value,ConnectorType.And,OperatorType.NotEqual);
            conditionModelList.add(queryConditionModel);
        }
    }
    /**
     * Description: 大于
     * @param condition 为true拼接条件 false不拼接
     * @param column 查询字段
     * @param value 值
     * @return com.example.JavaWebApi.core.neo4j.Neo4jAbstractQueryWrapper
     * @author 杨泽
     * @date 2023/11/2 11:26
     */
    protected void baseGt(boolean condition,String column,Object value){
        if(condition){
            QueryConditionModel queryConditionModel=createCondition(column,value,ConnectorType.And,OperatorType.GreaterThan);
            conditionModelList.add(queryConditionModel);
        }
    }

    /**
     * Description: 大于等于
     * @param condition 为true拼接条件 false不拼接
     * @param column 查询字段
     * @param value 值
     * @return com.example.JavaWebApi.core.neo4j.Neo4jAbstractQueryWrapper
     * @author 杨泽
     * @date 2023/11/2 11:27
     */
    protected void baseGe(boolean condition,String column,Object value){
        if(condition){
            QueryConditionModel queryConditionModel=createCondition(column,value,ConnectorType.And,OperatorType.GreaterThanOrEqual);
            conditionModelList.add(queryConditionModel);
        }
    }
    /**
     * Description: 小于
     * @param condition 为true拼接条件 false不拼接
     * @param column 查询字段
     * @param value 值
     * @return com.example.JavaWebApi.core.neo4j.Neo4jAbstractQueryWrapper
     * @author 杨泽
     * @date 2023/11/2 11:27
     */
    protected void baseLt(boolean condition,String column,Object value){
        if(condition){
            QueryConditionModel queryConditionModel=createCondition(column,value,ConnectorType.And,OperatorType.LessThan);
            conditionModelList.add(queryConditionModel);
        }
    }
    /**
     * Description: 小于等于
     * @param condition 为true拼接条件 false不拼接
     * @param column 查询字段
     * @param value 值
     * @return com.example.JavaWebApi.core.neo4j.Neo4jAbstractQueryWrapper
     * @author 杨泽
     * @date 2023/11/2 11:27
     */
    protected void baseLe(boolean condition,String column,Object value){
        if(condition){
            QueryConditionModel queryConditionModel=createCondition(column,value,ConnectorType.And,OperatorType.LessThanOrEqual);
            conditionModelList.add(queryConditionModel);
        }
    }
    /**
     * Description: 模糊查询
     * @param condition 为true拼接条件 false不拼接
     * @param column 查询字段
     * @param value 值
     * @return com.example.JavaWebApi.core.neo4j.Neo4jAbstractQueryWrapper
     * @author 杨泽
     * @date 2023/11/2 11:27
     */
    protected void baseLike(boolean condition,String column,Object value){
        if(condition){
            QueryConditionModel queryConditionModel=createCondition(column,value,ConnectorType.And,OperatorType.Like);
            conditionModelList.add(queryConditionModel);
        }
    }
    /**
     * Description: 右模糊
     * @param condition 为true拼接条件 false不拼接
     * @param column 查询字段
     * @param value 值
     * @return com.example.JavaWebApi.core.neo4j.Neo4jAbstractQueryWrapper
     * @author 杨泽
     * @date 2023/11/2 11:28
     */
    protected void baseLikeRight(boolean condition,String column,Object value){
        if(condition){
            QueryConditionModel queryConditionModel=createCondition(column,value,ConnectorType.And,OperatorType.LikeRight);
            conditionModelList.add(queryConditionModel);
        }
    }
    /**
     * Description: 左模糊
     * @param condition 为true拼接条件 false不拼接
     * @param column 查询字段
     * @param value 值
     * @return com.example.JavaWebApi.core.neo4j.Neo4jAbstractQueryWrapper
     * @author 杨泽
     * @date 2023/11/2 11:28
     */
    protected void baseLikeLeft(boolean condition,String column,Object value){
        if(condition){
            QueryConditionModel queryConditionModel=createCondition(column,value,ConnectorType.And,OperatorType.LikeLeft);
            conditionModelList.add(queryConditionModel);
        }
    }
    /**
     * Description:模糊取反
     * @param condition 为true拼接条件 false不拼接
     * @param column 查询字段
     * @param value 值
     * @return com.example.JavaWebApi.core.neo4j.Neo4jAbstractQueryWrapper
     * @author 杨泽
     * @date 2023/11/2 11:28
     */
    protected void baseNotLike(boolean condition,String column,Object value){
        if(condition){
            QueryConditionModel queryConditionModel=createCondition(column,value,ConnectorType.And,OperatorType.NotLike);
            conditionModelList.add(queryConditionModel);
        }
    }
    /**
     * Description: 包含
     * @param condition 为true拼接条件 false不拼接
     * @param column 查询字段
     * @param coll 集合
     * @return com.example.JavaWebApi.core.neo4j.Neo4jAbstractQueryWrapper
     * @author 杨泽
     * @date 2023/11/2 11:28
     */
    protected void baseIn(boolean condition, String column, Collection<?> coll){
        if(condition){
            QueryConditionModel queryConditionModel=createCondition(column,coll,ConnectorType.And,OperatorType.In);
            conditionModelList.add(queryConditionModel);
        }
    }
    /**
     * Description: 不包含
     * @param condition 为true拼接条件 false不拼接
     * @param column 查询字段
     * @param coll 集合
     * @return com.example.JavaWebApi.core.neo4j.Neo4jAbstractQueryWrapper
     * @author 杨泽
     * @date 2023/11/2 11:29
     */
    protected void baseNotIn(boolean condition,String column,Collection<?> coll){
        if(condition){
            QueryConditionModel queryConditionModel=createCondition(column,coll,ConnectorType.And,OperatorType.NotIn);
            conditionModelList.add(queryConditionModel);
        }
    }
    protected void baseLabel(Boolean condition,String parameterName,Object value){
        if(condition){
            QueryConditionModel queryConditionModel=createCondition(parameterName,value,ConnectorType.And,OperatorType.Label);
            conditionModelList.add(queryConditionModel);
        }
    }

    protected void baseNotLabel(Boolean condition,String parameterName,Object value){
        if(condition){
            QueryConditionModel queryConditionModel=createCondition(parameterName,value,ConnectorType.And,OperatorType.NotLabel);
            conditionModelList.add(queryConditionModel);
        }
    }

    protected void baseType(Boolean condition,String parameterName,Object value){
        if(condition){
            QueryConditionModel queryConditionModel=createCondition(parameterName,value,ConnectorType.And,OperatorType.Type);
            conditionModelList.add(queryConditionModel);
        }
    }

    protected void baseNotType(Boolean condition,String parameterName,Object value){
        if(condition){
            QueryConditionModel queryConditionModel=createCondition(parameterName,value,ConnectorType.And,OperatorType.NotType);
            conditionModelList.add(queryConditionModel);
        }
    }

    protected void baseId(Boolean condition,String parameterName,Object value){
        if(condition){
            QueryConditionModel queryConditionModel=createCondition(parameterName,value,ConnectorType.And,OperatorType.Id);
            conditionModelList.add(queryConditionModel);
        }
    }
    protected void baseNotId(Boolean condition,String parameterName,Object value){
        if(condition){
            QueryConditionModel queryConditionModel=createCondition(parameterName,value,ConnectorType.And,OperatorType.NotId);
            conditionModelList.add(queryConditionModel);
        }
    }

    /**
     * Description: 直接拼接语句
     * @param condition 为true拼接条件 false不拼接
     * @param sql 拼接语句
     * @return com.example.JavaWebApi.core.neo4j.Neo4jAbstractQueryWrapper
     * @author 杨泽
     * @date 2023/11/2 11:30
     */
    protected void baseApplySql(boolean condition,String sql){
        if(condition){
            appendSqls.add(sql);
        }
    }
    protected void baseObject2CQL(String parameterName,Map<String,Object> map){
        this.objectMap.put(parameterName,map);
    }
    /**
     * Description: 正序排序
     * @param condition 为true拼接条件 false不拼接
     * @param column 排序字段
     * @return com.example.JavaWebApi.core.neo4j.Neo4jAbstractQueryWrapper
     * @author 杨泽
     * @date 2023/11/2 11:32
     */
    protected void baseOrderByAsc(boolean condition,String column){
        if(condition){
            this.orderByAsc.add(column);
        }
    }
    /**
     * Description: 倒叙排序
     * @param condition 为true拼接条件 false不拼接
     * @param column 排序字段
     * @return com.example.JavaWebApi.core.neo4j.Neo4jAbstractQueryWrapper
     * @author 杨泽
     * @date 2023/11/2 11:32
     */
    protected void baseOrderByDesc(boolean condition,String column){
        if(condition){
            this.orderByDesc.add(column);
        }
    }
    /**
     * Description: 构造器生成语句
     * @param wrapperIndex 构造器索引
     * @return java.lang.String
     * @author 杨泽
     * @date 2023/11/2 11:33
     */
    public String build(Integer wrapperIndex){
        if(!hasBuild){
            hasBuild=true;
            if(wrapperIndex==null){
                wrapperIndex=0;
            }
            StringBuilder stringBuilder=new StringBuilder(" 1=1 ");
            for(QueryConditionModel conditionModel : conditionModelList){
                stringBuilder.append(getConnectSql(conditionModel.getConnectorType())
                        +getOperatorSql(conditionModel.getOperatorType(),
                        conditionModel.getColumn(),conditionModel.getValue(),wrapperIndex));
            }
            for(Map.Entry<String,Map<String,Object>> entry:objectMap.entrySet()){
                String cql=convert2String(entry.getValue(),wrapperIndex);
                objectCql.put(entry.getKey(),cql);
            }
            StringBuilder stringBuilder1=new StringBuilder();
            if(orderByAsc.size()>0||orderByDesc.size()>0){
                stringBuilder1.append(" order by ");
                for(String asc : orderByAsc){
                    itemIndex++;
                    parameters.put("orderBy"+"_"+wrapperIndex+"_"+itemIndex,asc);
                    stringBuilder1.append(asc);
                    stringBuilder1.append(" asc,");
                }
                for (String desc :orderByDesc){
                    itemIndex++;
                    parameters.put("orderBy"+"_"+wrapperIndex+"_"+itemIndex,desc);
                    stringBuilder1.append(desc);
                    stringBuilder1.append(" desc,");
                }
                stringBuilder1.deleteCharAt(stringBuilder1.length()-1);
                stringBuilder1.append(" ");
                finalOrderCql=stringBuilder1.toString();
            }
            for (String sql : appendSqls){
                stringBuilder.append(sql);
            }
            finalConditionCql=stringBuilder.toString();
        }
        return finalConditionCql;
    }
    protected String convert2String(Map<String,Object> hashMap,Integer wrapperIndex){
        StringBuilder sb=new StringBuilder("{");
        for(Map.Entry<String,Object> entry :hashMap.entrySet()){
            sb.append("`");
            sb.append(entry.getKey());
            sb.append("`");
            sb.append(":");
            String parameterName=entry.getKey()+"_"+wrapperIndex+"_"+itemIndex;
            sb.append(getParameterCql(parameterName));
            sb.append(",");
            this.parameters.put(parameterName,entry.getValue());
            itemIndex++;
        }
        sb.deleteCharAt(sb.length()-1);
        sb.append("}");
        return sb.toString();
    }

    protected String getConnectSql(ConnectorType connectorType){
        switch (connectorType){
            case Or:
                return " or ";
            default:
                return " and ";
        }
    }

    protected String getOperatorSql(OperatorType operatorType,String column,Object value,Integer wrapperIndex){
        String sql="";
        switch (operatorType){
            case Equal:
                sql="`"+column+"`="+getObjectSql(value,operatorType.toString(),wrapperIndex);
                break;
            case NotEqual:
                sql="`"+column+"`!="+getObjectSql(value,operatorType.toString(),wrapperIndex);
                break;
            case LessThan:
                sql="`"+column+"`<"+getObjectSql(value,operatorType.toString(),wrapperIndex);
                break;
            case LessThanOrEqual:
                sql="`"+column+"`<="+getObjectSql(value,operatorType.toString(),wrapperIndex);
                break;
            case GreaterThan:
                sql="`"+column+"`>"+getObjectSql(value,operatorType.toString(),wrapperIndex);
                break;
            case GreaterThanOrEqual:
                sql="`"+column+"`>="+getObjectSql(value,operatorType.toString(),wrapperIndex);
                break;
            case In:
                sql="`"+column+"` in "+ getObjectSql(value,operatorType.toString(),wrapperIndex);
                break;
            case NotIn:
                sql=" not "+"`"+column+"` in "+ getObjectSql(value,operatorType.toString(),wrapperIndex);
                break;
            case Like:
                sql="`"+column+"` contains "+getObjectSql(value,operatorType.toString(),wrapperIndex);
                break;
            case NotLike:
                sql=" not "+"`"+column+"` contains  "+getObjectSql(value,operatorType.toString(),wrapperIndex);
                break;
            case LikeLeft:
                sql="`"+column+"` end with "+getObjectSql(value,operatorType.toString(),wrapperIndex);
                break;
            case LikeRight:
                sql=" not `"+column+"` end with "+getObjectSql(value,operatorType.toString(),wrapperIndex);
                break;
            case Label:
                sql=getObjectSql(value,operatorType.toString(),wrapperIndex)+" IN labels("+column+")";
                break;
            case NotLabel:
                sql=" not "+getObjectSql(value,operatorType.toString(),wrapperIndex)+" IN labels("+column+")";
                break;
            case Type:
                sql=" type(`"+column+"`)="+getObjectSql(value,operatorType.toString(),wrapperIndex);
                break;
            case NotType:
                sql=" not type(`"+column+"`)="+getObjectSql(value,operatorType.toString(),wrapperIndex);
                break;
            case Id:
                sql=" id(`"+column+"`)="+getObjectSql(value,operatorType.toString(),wrapperIndex);
                break;
            case NotId:
                sql=" not id(`"+column+"`)="+getObjectSql(value,operatorType.toString(),wrapperIndex);
                break;
            default:
        }
        return sql;
    }

    protected String getObjectSql(Object value,String parameterName,Integer wrapperIndex){
        String sql;
        Class<?> classes=value.getClass();
        if(Collection.class.isAssignableFrom(classes)){
            Collection<?> collection=(Collection<?>)value;
            if(collection.isEmpty()){
                return "[]";
            }
            else {
                StringBuilder stringBuilder=new StringBuilder("[");
                sql="[";
                for(Object item : collection){
                    String param=parameterName+"_"+wrapperIndex+"_"+itemIndex;
                    itemIndex++;
                    parameters.put(param,item);
                    //stringBuilder.append(getValueSql(item));
                    stringBuilder.append(getParameterCql(param));
                    stringBuilder.append(",");
                }
                stringBuilder.deleteCharAt(stringBuilder.length()-1);
                stringBuilder.append("]");
                sql=stringBuilder.toString();
            }
        }
        else {
            String param=parameterName+"_"+wrapperIndex+"_"+itemIndex;
            parameters.put(param,value);
            sql=getParameterCql(param);
            itemIndex++;
        }
        return sql;
    }
    protected String getParameterCql(String parameterName){
        return "$"+parameterName;
    }

    protected QueryConditionModel createCondition(String column,Object value,ConnectorType connectorType,OperatorType operatorType){
        QueryConditionModel queryConditionModel=new QueryConditionModel();
        queryConditionModel.setColumn(column);
        queryConditionModel.setValue(value);
        queryConditionModel.setConnectorType(connectorType);
        queryConditionModel.setOperatorType(operatorType);
        return queryConditionModel;
    }
    protected void mergeParameter(Neo4jAbstractQueryWrapper wrapper){
        for(Map.Entry<String,Object> entry:wrapper.getParameters().entrySet()){
            this.parameters.put(entry.getKey(),entry.getValue());
        }
    }
    protected <T extends Neo4jAbstractQueryWrapper> void mergeParameter(List<T> wrappers){
        for(Neo4jAbstractQueryWrapper wrapper:wrappers){
            mergeParameter(wrapper);
        }
    }
}